<?php

namespace seraph_pds;

// Exit if accessed directly
if( !defined( 'ABSPATH' ) )
	exit;

// #######################################################################
// Gen

class Gen
{
	const SEVERITY_SUCCESS							= 0;
	const SEVERITY_ERROR							= 1;

	const FACILITY_INTERNET							= 12;
	const FACILITY_HTTP								= 25;

	const S_OK										= 0x00000000;	// S_OK
	const S_FALSE									= 0x00000001;	// S_FALSE
	const E_INVALID_STATE							= 0x8007139F;	// ERROR_INVALID_STATE
	const E_INVALIDARG								= 0x80070057;	// E_INVALIDARG
	const E_INTERNAL								= 0x8007054F;	// ERROR_INTERNAL_ERROR
	const E_FAIL									= 0x80004005;	// E_FAIL
	const E_DATACORRUPTED							= 0x80070570;	// MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_CORRUPT )

	static function HrMake( $sev, $fac, $code )
	{
		return( ( $sev << 31 ) | ( $fac << 16 ) | $code );
	}

	static function HrCode( $hr )
	{
		return( ( ( $hr ) & 0xFFFF ) );
	}

	static function HrFacility( $hr )
	{
		return( ( ( ( $hr ) >> 16 ) & 0x1FFF ) );
	}

	static function HrSucc( $hr )
	{
		return( $hr < 0x80000000 );
	}

	static function GetSiteId()
	{
		$siteUrlParts = @parse_url( get_site_url() );
		if( !is_array( $siteUrlParts ) )
			return( '' );

		$res = $siteUrlParts[ 'host' ];

		$port = @$siteUrlParts[ 'port' ];
		if( $port )
			$res .= '_' . $port;

		$path = @$siteUrlParts[ 'path' ];
		if( $path )
			$res .= '_' . str_replace( array( '/', '\\' ), '_', $path );

		return( md5( $res ) );
	}

	static function GetSiteDisplayName()
	{
		$siteUrlParts = @parse_url( get_site_url() );
		if( !is_array( $siteUrlParts ) )
			return( '' );

		$res = $siteUrlParts[ 'host' ];

		$port = @$siteUrlParts[ 'port' ];
		if( $port )
			$res .= ':' . $port;

		$path = @$siteUrlParts[ 'path' ];
		if( $path )
			$res .= '/' . $path;

		return( $res );
	}

	static function GetArrField( $arr, $fieldPath, $defVal = null, $sep = '.' )
	{
		if( !is_array( $arr ) )
			return( $defVal );

		if( !is_array( $fieldPath ) )
			$fieldPath = explode( $sep, $fieldPath );
		return( self::_GetArrField( $arr, $fieldPath, $defVal ) );
	}

	static private function _GetArrField( $v, array $fieldPath, $defVal = null )
	{
		if( !count( $fieldPath ) )
			return( $defVal );

		foreach( $fieldPath as $fld )
		{
			if( !is_array( $v ) )
				return( $defVal );

			$v = @$v[ $fld ];
			if( $v === null && !isset( $v[ $fld ] ) )
				return( $defVal );
		}

		return( $v );
	}

	static function SetArrField( &$arr, $fieldPath, $val = null, $sep = '.' )
	{
		if( !is_array( $fieldPath ) )
			$fieldPath = explode( $sep, $fieldPath );
		self::_SetArrField( $arr, $fieldPath, $val );
	}

	static private function _SetArrField( &$arr, array $fieldPath, $val = null )
	{
		$n = count( $fieldPath );
		if( !$n )
			return;

		$fld = array_shift( $fieldPath );
		if( !count( $fieldPath ) )
			$arr[ $fld ] = $val;
		else
		{
			if( !is_array( $arr[ $fld ] ) )
				$arr[ $fld ] = array();
			self::_SetArrField( $arr[ $fld ], $fieldPath, $val );
		}
	}

	static function ToUnixSlashes( $path )
	{
		return( str_replace( '\\', '/', $path ) );
	}

	static function DoesFuncExist( $name )
	{
		$classSep = strpos( $name, '::' );
		if( $classSep === false )
			return( function_exists( $name ) );

		return( method_exists( substr( $name, 0, $classSep ), substr( $name, $classSep + 2 ) ) );
	}

	// #######################################################################
	// Serialize

	static function Serialize( $v )
	{
		return( @serialize( $v ) );
	}

	static function Unserialize( $data, $defVal = null )
	{
		if( !is_serialized( $data ) )
			return( $defVal );

		$v = @unserialize( $data );
		if( $v === false )
			return( $defVal );

		return( $v );
	}

	// #######################################################################
	// Crypt/Decrypt

	const CRYPT_METHOD_OPENSSL					= 'os';
	const CRYPT_METHOD_MCRYPT					= 'mc';
	const CRYPT_METHOD_XOR						= 'x';

	static function StrEncode( $str, $type = null )
	{
		if( empty( $str ) || !is_string( $str ) )
			return( '' );

		if( empty( $type ) )
		{
			if( false ) {}
			else if( function_exists( 'openssl_encrypt' ) )
				$type = self::CRYPT_METHOD_OPENSSL;
			else if( function_exists( 'mcrypt_encrypt' ) )
				$type = self::CRYPT_METHOD_MCRYPT;
			else
				$type = self::CRYPT_METHOD_XOR;
		}

		switch( $type )
		{
		case self::CRYPT_METHOD_OPENSSL:
			if( !function_exists( 'openssl_encrypt' ) )
				return( '' );

			$key = openssl_digest( wp_salt(), 'SHA256', true );

			$ivSize = ( function_exists( 'openssl_cipher_iv_length' ) && function_exists( 'openssl_random_pseudo_bytes' ) ) ? openssl_cipher_iv_length( 'AES-256-CBC' ) : null;
			$iv = null;
			if( $ivSize )
				$iv = openssl_random_pseudo_bytes( $ivSize );

			$str = openssl_encrypt( $str, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv );
			if( $str === false )
				return( '' );

			if( $ivSize )
				$str = $iv . $str;
			break;

		case self::CRYPT_METHOD_MCRYPT:
			if( !function_exists( 'mcrypt_encrypt' ) )
				return( '' );

			$key = md5( wp_salt(), true );
			$str = mcrypt_encrypt( MCRYPT_RIJNDAEL_256, $key, $str, MCRYPT_MODE_ECB );
			if( $str === false )
				return( '' );
			break;

		case self::CRYPT_METHOD_XOR:
			$str = self::XorData( $str, wp_salt() );
			break;

		default:
			return( '' );
			break;
		}

		$str = $type . ':' . base64_encode( $str );
		return( $str );
	}

	static function StrDecode( $str )
	{
		if( empty( $str ) || !is_string( $str ) )
			return( '' );

		$type = substr( $str, 0, 3 );
		{
			$sep = strpos( $type, ':' );
			if( $sep === false )
				$type = self::CRYPT_METHOD_MCRYPT;
			else
			{
				$type = substr( $type, 0, $sep );
				$str = substr( $str, $sep + 1 );
			}
		}

		$str = base64_decode( $str );

		switch( $type )
		{
		case self::CRYPT_METHOD_OPENSSL:
			if( !function_exists( 'openssl_decrypt' ) )
				return( '' );

			$key = openssl_digest( wp_salt(), 'SHA256', true );

			$ivSize = ( function_exists( 'openssl_cipher_iv_length' ) && function_exists( 'openssl_random_pseudo_bytes' ) ) ? openssl_cipher_iv_length( 'AES-256-CBC' ) : null;
			$iv = null;
			if( $ivSize )
			{
				$iv = substr( $str, 0, $ivSize );
				$str = substr( $str, $ivSize );
			}

			$str = openssl_decrypt( $str, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv );
			if( $str === false )
				$str = '';
			break;

		case self::CRYPT_METHOD_MCRYPT:
			if( !function_exists( 'mcrypt_decrypt' ) )
				return( '' );

			$key = md5( wp_salt(), true );
			$str = mcrypt_decrypt( MCRYPT_RIJNDAEL_256, $key, $str, MCRYPT_MODE_ECB );
			if( $str === false )
				$str = '';
			break;

		case self::CRYPT_METHOD_XOR:
			$str = self::XorData( $str, wp_salt() );
			break;

		default:
			return( '' );
			break;
		}

		return( $str );
	}

	static function XorData( $data, $key )
	{
		$n = strlen( $data );
		$nKey = strlen( $key );

		if( !$nKey )
			return( null );

		$dataNew = '';
		for( $i = 0, $iKey = 0; $i < $n; $i++, $iKey++ )
		{
			if( $iKey == $nKey )
				$iKey = 0;
			$dataNew .= $data[ $i ] ^ $key[ $iKey ];
		}

		return( $dataNew );
	}

	static function HtAccess_SetBlock( $id, $content )
	{
		$homePath = get_home_path();
		$htaccessFile = $homePath . '.htaccess';

		if( !( ( !file_exists( $htaccessFile ) && is_writable( $homePath ) ) || is_writable( $htaccessFile ) ) )
			return( Gen::S_FALSE );

		if( !got_mod_rewrite() )
			return( Gen::S_FALSE );

		return( insert_with_markers( $htaccessFile, $id, $content ) ? Gen::S_OK : Gen::S_FALSE );
	}

	static function HtAccess_QuoteUri( $uri )
	{
		// preg_quote()
		$uri = str_replace( '.', '\\.', $uri );
		$uri = str_replace( '?', '\\?', $uri );
		return( $uri );
	}
}

// #######################################################################
// Net

class Net
{
	const E_TIMEOUT									= 0x800C2EE2;	// MAKE_HRESULT( SEVERITY_ERROR, FACILITY_INTERNET, ERROR_INTERNET_TIMEOUT )

	const E_HTTP_STATUS_BEGIN						= 0x100;
	const E_HTTP_STATUS_END							= 0x300;

	static function GetHrFromResponseCode( $code )
	{
		return( Gen::HrMake( $code < 400 ? Gen::SEVERITY_SUCCESS : Gen::SEVERITY_ERROR, Gen::FACILITY_HTTP, Net::E_HTTP_STATUS_BEGIN + $code ) );
	}

	static function GetHrFromWpRemoteGet( $requestRes )
	{
		if( !$requestRes )
			return( Gen::E_FAIL );

		if( !is_wp_error( $requestRes ) )
		{
			$httpStatus = wp_remote_retrieve_response_code( $requestRes );
			if( $httpStatus == 200 )
				return( Gen::S_OK );
			return( Net::GetHrFromResponseCode( $httpStatus ) );
		}

		$errCode = $requestRes -> get_error_code();
		$errMsg = $requestRes -> get_error_message( $errCode );

		if( $errCode == 'http_request_failed' && strpos( $errMsg, 'cURL error 28:' ) !== false )
			return( Net::E_TIMEOUT );

		return( Gen::E_FAIL );
	}
}

// #######################################################################
// #######################################################################
